package remoting.grpc;

import common.exception.RemotingException;
import common.model.Codec2;
import common.model.MagicUrl;
import common.util.ExecutorUtil;
import common.util.NetUtils;
import io.grpc.netty.NettyServerBuilder;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import remoting.AbstractServer;
import remoting.Server;
import remoting.channel.Channel;
import remoting.channel.ChannelHandler;
import remoting.channel.ChannelHandlers;
import threadpools.ThreadPool;

public class GrpcServer extends AbstractServer implements Server {

  private static final Logger logger = LoggerFactory.getLogger(GrpcServer.class);

  private io.grpc.Server server;

  private Map<String, Channel> channels;

  public GrpcServer(MagicUrl url, ChannelHandler handler, ThreadPool threadPool,
      Codec2 codec)
      throws RemotingException {
    super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME), threadPool), codec);
  }

  @Override
  protected void doOpen() throws Throwable {
    GrpcHandler grpcHandler = new GrpcHandler(getUrl(), this, getCodec());
    server = NettyServerBuilder.forPort(getBindAddress().getPort()).addService(grpcHandler).build().start();
    channels = grpcHandler.getChannels();
    logger.info("Grpc server started, listening on " + getBindAddress().getPort());
  }

  @Override
  protected void doClose() throws Throwable {
    server.shutdown();
  }

  @Override
  public boolean isBound() {
    return server.isTerminated();
  }

  @Override
  public Collection<Channel> getChannels() {
    return channels.values();
  }

  @Override
  public Channel getChannel(InetSocketAddress remoteAddress) {
    return channels.get(NetUtils.toAddressString(remoteAddress));
  }
  @Override
  public boolean canHandleIdle(){
    return true;
  }
}
